#define NOMINMAX
#include "FI_GMKTIndexData.h"
#include <bondlib/BondCalendar.h>
#include <core/time/time.h>
#include <msgcenter/FIMsgProcess.h>
#include <qbkernel/include/qb_base.h>
#include <qbprotocol/include/rdProto.h>
#include <qbprotocol/include/SSIRSModel.h>
#include <qbtools/message/MessagePoster.h>
#include <uam/UserAccountManager.h>
#include "../StringResource.h"

struct GMktIndex
{
    qb::base::Mutex m_lock;
    bool selected{false};
    std::string m_sId;          //指标代码
    char   m_price[16];			//最新价
    char   m_updownValue[16];	//涨跌幅
    char   m_updownPoint[16];	//涨跌点
    time_t m_time{0};				//最终时间
};

static std::map<const std::string, int> m_index_code_2_id;

FIGMktIndexPriceData::FIGMktIndexPriceData()
{
    for(int i = 0; i < (int)m_GMktIndexPriceData.size(); ++i) {
        m_GMktIndexPriceData[i] = new GMktIndex;
        m_GMktIndexPriceData[i]->m_sId = NewStringTable::FixedAssetsIndexId(i).toStdString();
    }

    if (m_index_code_2_id.empty()) {
        for(int i = 0; i < (int)m_GMktIndexPriceData.size(); ++i) {
            m_index_code_2_id[m_GMktIndexPriceData[i]->m_sId] = i;
        }
    }
}

FIGMktIndexPriceData::~FIGMktIndexPriceData()
{
    for(int i = 0; i < (int)m_GMktIndexPriceData.size(); ++i) {
        delete m_GMktIndexPriceData[i];
        m_GMktIndexPriceData[i] = nullptr;
    }
}

void FIGMktIndexPriceData::reqData(MessageReceiver* msgRecv, const std::vector<int> current_indexes)
{
    xBatchGMktIndexPriceReq_c req;
    FIELDCOPY(req.m_UserId, SSUserAccountManager::instance().GetUserInfo().m_UserId);
    FIELDCOPY(req.m_CompanyId, SSUserAccountManager::instance().GetUserInfo().m_CompanyId);

    // m_sId will not be modified -- so no lock here
    for(const auto& data : m_GMktIndexPriceData) {
        //if (!data.selected)
        //    continue;
        req.m_Indexes.push_back(data->m_sId);
    }

    qb::SSRequestMsg msg;
    msg.m_pRequest = &req;
    msg.m_FuncID = E_FID_QB_BATCH_GMKT_INDEX_PRICE_REQ;
    MessagePoster poster(&msg, qbmsg::fixedincome::EncodeFunc);
    poster.send(msgRecv);

    std::array<bool, MaxCount> index_2_select;
    std::fill(index_2_select.begin(), index_2_select.end(), 42);
    for (const auto& index : current_indexes) {
        if ((index >= 0) && (index < (int)index_2_select.size()))
            index_2_select[index] = true;
    }

    for(int i = 0; i < (int)m_GMktIndexPriceData.size(); ++i) {
        selectIndex(msgRecv, (GMktIndexID)i, index_2_select[i]);
    }
}

int FIGMktIndexPriceData::onReceive(int32_t funcId, const qb::SSAckMsg& msg)
{
    switch (funcId) {
    case E_FID_QB_BATCH_GMKT_INDEX_PRICE_REQ: {
        xBatchGMktIndexPriceAck_c* pdata = (xBatchGMktIndexPriceAck_c*)msg.m_pRet;
        if (!pdata) return -1;

        for (const xGMktIndexPriceUpDownUnit_c& unit : pdata->m_IndexList) {
            const auto iter = m_index_code_2_id.find(unit.m_IndexId);
            if (iter == m_index_code_2_id.end()) {
                // assert false
                continue;
            }

            const int unit_id = iter->second;

            SCOPED_MUTEX(m_GMktIndexPriceData[unit_id]->m_lock);
            FIELDCOPY(m_GMktIndexPriceData[unit_id]->m_price, unit.m_Price);
            FIELDCOPY(m_GMktIndexPriceData[unit_id]->m_updownValue, unit.m_UpDownPercent);
            FIELDCOPY(m_GMktIndexPriceData[unit_id]->m_updownPoint, unit.m_UpDownPoint);
            m_GMktIndexPriceData[unit_id]->m_time = unit.m_DateTime;
        }
        return GMktIndexID::MaxCount;
    } break;
    case E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_PUSH: {
        xGMktIndexPriceUpDownAck_c* pdata = (xGMktIndexPriceUpDownAck_c*)msg.m_pRet;
        if (!pdata) return -2;
        const auto iter = m_index_code_2_id.find(pdata->m_IndexId);
        if (iter == m_index_code_2_id.end()) {
            return -3;
        }

        const int unit_id = iter->second;
        SCOPED_MUTEX(m_GMktIndexPriceData[unit_id]->m_lock);
        FIELDCOPY(m_GMktIndexPriceData[unit_id]->m_price, pdata->m_Price);
        FIELDCOPY(m_GMktIndexPriceData[unit_id]->m_updownValue, pdata->m_UpDownPercent);
        FIELDCOPY(m_GMktIndexPriceData[unit_id]->m_updownPoint, pdata->m_UpDownPoint);
        m_GMktIndexPriceData[unit_id]->m_time = pdata->m_DateTime;

        return unit_id;
    } break;
    case E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_CANCEL: {
    } break;
    default: {
        return -4;
    } break;
    }

    return -5;
}

bool FIGMktIndexPriceData::getData(const GMktIndexID& index_id, QString& price, QString& updownValue, QString& updownPoint, time_t& time) {
    if ((0 <= index_id) && (index_id < (int)m_GMktIndexPriceData.size())) {
        SCOPED_MUTEX(m_GMktIndexPriceData[index_id]->m_lock);
        price = m_GMktIndexPriceData[index_id]->m_price;
        updownValue = m_GMktIndexPriceData[index_id]->m_updownValue;
        updownPoint = m_GMktIndexPriceData[index_id]->m_updownPoint;
        time = m_GMktIndexPriceData[index_id]->m_time;

        return true;
    }

    return false;
}

static void reqPush(const bool& start, MessageReceiver* msgRecv, const std::string& index_id) {
    xGMktIndexPriceUpDownReq_c req;
    FIELDCOPY(req.m_UserId, SSUserAccountManager::instance().GetUserInfo().m_UserId);
    FIELDCOPY(req.m_CompanyId, SSUserAccountManager::instance().GetUserInfo().m_CompanyId);
    FIELDCOPY(req.m_IndexId, index_id.c_str());

    qb::SSRequestMsg msg;
    msg.m_pRequest = &req;
    msg.m_FuncID = start ? E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_PUSH : E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_CANCEL;
    MessagePoster poster(&msg, qbmsg::fixedincome::EncodeFunc);
    poster.send(msgRecv);

    if (start) {
        PushMsgInfo pmi3(E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_PUSH, "", nullptr);
        msg.m_FuncID = E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_PUSH;
        msgRecv->registPush(pmi3, &msg, qbmsg::fixedincome::EncodeFunc);
    } else {
        PushMsgInfo pmi3(E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_CANCEL, "", nullptr);
        msg.m_FuncID = E_FID_QB_FIXEDASSETS_GMKT_INDEX_PRICE_CANCEL;
        msgRecv->unRegistPush(pmi3, &msg, qbmsg::fixedincome::EncodeFunc);
    }
}

void FIGMktIndexPriceData::selectIndex(MessageReceiver* msgRecv, const GMktIndexID &index_id, const bool &select)
{
    if ((0 <= index_id) && (index_id < (int)m_GMktIndexPriceData.size())) {
        SCOPED_MUTEX(m_GMktIndexPriceData[index_id]->m_lock);
        bool& origin = m_GMktIndexPriceData[index_id]->selected;
        if (origin != select) {
            origin = select;
            reqPush(select, msgRecv, m_GMktIndexPriceData[index_id]->m_sId);
        }
    }
}
